/**
 *	@file    matrixssllib.h
 *	@version 8e6f0e1 (HEAD -> master)
 *
 *	Internal header file used for the MatrixSSL implementation..
 *	Only modifiers of the library should be intersted in this file
 */
/*
 *	Copyright (c) 2013-2016 INSIDE Secure Corporation
 *	Copyright (c) PeerSec Networks, 2002-2011
 *	All Rights Reserved
 *
 *	The latest version of this code is available at http://www.matrixssl.org
 *
 *	This software is open source; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This General Public License does NOT permit incorporating this software
 *	into proprietary programs.  If you are unable to comply with the GPL, a
 *	commercial license for this software may be purchased from INSIDE at
 *	http://www.insidesecure.com/
 *
 *	This program is distributed in WITHOUT ANY WARRANTY; without even the
 *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *	See the GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *	http://www.gnu.org/copyleft/gpl.html
 */
/******************************************************************************/

#ifndef _h_MATRIXSSLLIB
#define _h_MATRIXSSLLIB

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************/
/**
	Additional 'hidden' TLS configuration here for deprecated support.
	@security These options allow enabling/disabling features that have been
	found to generally considered weak and should not be changed except for
	compatibility with older software that cannot be changed.
	@security The default value for strongest security is indicated for each
	option.
*/
/** Deprecated cipher suites. */
#ifndef USE_DTLS
//#define USE_SSL_RSA_WITH_RC4_128_MD5 /**< @security OFF */
//#define USE_SSL_RSA_WITH_RC4_128_SHA /**< @security OFF */
//#define USE_TLS_RSA_WITH_SEED_CBC_SHA /**< @security OFF */
//#define USE_TLS_RSA_WITH_IDEA_CBC_SHA /**< @security OFF */
#endif

/** Anonymous, non authenticated ciphers. */
//#define USE_TLS_DH_anon_WITH_AES_128_CBC_SHA /**< @security OFF */
//#define USE_TLS_DH_anon_WITH_AES_256_CBC_SHA /**< @security OFF */
//#define USE_SSL_DH_anon_WITH_3DES_EDE_CBC_SHA /**< @security OFF */
#ifndef USE_DTLS
//#define USE_SSL_DH_anon_WITH_RC4_128_MD5 /**< @security OFF */
#endif

/** Authenticated but not encrypted ciphers. */
//#define USE_SSL_RSA_WITH_NULL_SHA /**< @security OFF */
//#define USE_SSL_RSA_WITH_NULL_MD5 /**< @security OFF */

/**
	False Start support for Chrome browser.
	@see http://tools.ietf.org/html/draft-bmoeller-tls-falsestart-00

	@note April 2012: Google has announced this feature will be removed in
	version 20 of their browser due to industry compatibility issues.

	@note November 2016: An official IETF draft is in process for this
	functionality to become standardized.
	@see https://datatracker.ietf.org/doc/draft-ietf-tls-falsestart/
*/
//#define ENABLE_FALSE_START /**< @security OFF */

/**
	zlib compression support.
	@security The CRIME attack on HTTPS has shown that compression at the
	TLS layer can introduce vulnerabilities in higher level protocols. It is
	recommended to NOT use compression features at the TLS level.
*/
//#define USE_ZLIB_COMPRESSION /**< @security OFF NIST_SHOULD_NOT */

/******************************************************************************/
/**
	Rehandshaking support.
	In late 2009 An "authentication gap" exploit was discovered in the
	SSL re-handshaking protocol.  The fix to the exploit was introduced
	in RFC 5746 and is referred to here	as SECURE_REHANDSHAKES.

	ENABLE_SECURE_REHANDSHAKES implements RFC 5746 and will securely
	renegotiate with any implementations that support it.  It is
	recommended to leave this disabled unless there is a specific requirement
	to support it.

	By enabling REQUIRE_SECURE_REHANDSHAKES, the library will test that each
	communicating peer that is attempting to connect has implemented
	RFC 5746 and will terminate handshakes with any that have not.

	If working with SSL peers that have not implemented RFC 5746 and
	rehandshakes are required, you may enable ENABLE_INSECURE_REHANDSHAKES
	but it is NOT RECOMMENDED

	It is a conflict to enable both ENABLE_INSECURE_REHANDSHAKES and
	REQUIRE_SECURE_REHANDSHAKES and a compile error will occur

	To completely disable rehandshaking comment out all three of these defines

	@security Disabling handshaking altogether is the most secure. If it must
	be enabled, only secure rehandshakes should be allowed. Other modes below
	are provided only for compatibility with old TLS/SSL libraries.
*/
#ifdef USE_REHANDSHAKING
//#define ENABLE_SECURE_REHANDSHAKES /**< @security OFF NIST_SHALL */
#define REQUIRE_SECURE_REHANDSHAKES /**< @security ON NIST_SHALL */
//#define ENABLE_INSECURE_REHANDSHAKES /** @security OFF NIST_SHALL_NOT */
#endif

/******************************************************************************/
/**
	Beast Mode.
	In Sept. 2011 security researchers demonstrated how a previously known
	CBC encryption weakness could be used to decrypt HTTP data over SSL.
	The attack was named BEAST (Browser Exploit Against SSL/TLS).

	This issue only affects TLS 1.0 (and SSL) and only if the cipher suite
	is using a symmetric CBC block cipher.  Enable USE_TLS_1_1 above to
	completely negate this workaround if TLS 1.1 is also supported by peers.

	As with previous SSL vulnerabilities, the attack is generally considered
	a very low risk for individual browsers as it requires the attacker
	to have control over the network to become a MITM.  They will also have
	to have knowledge of the first couple blocks of underlying plaintext
	in order to mount the attack.

	A zero length record proceeding a data record has been a known fix to this
	problem for years and MatrixSSL has always supported the handling of empty
	records. So alternatively, an implementation could always encode a zero
	length record before each record encode. Some old SSL implementations do
	not handle decoding zero length records, however.

	This BEAST fix is on the client side and moves the implementation down to
	the SSL library level so users do not need to manually send zero length
	records. This fix uses the same IV obfuscation logic as a zero length
	record by breaking up each application data record in two. Because some
	implementations don't handle zero-length records, the the first record
	is the first byte of the plaintext message, and the second record
	contains the remainder of the message.

	This fix is based on the workaround implemented in Google Chrome:
	http://src.chromium.org/viewvc/chrome?view=rev&revision=97269

	This workaround adds approximagely 53 bytes to the encoded length of each
	SSL3.0 or TLS1.0 record that is encoded, due to the additional header,
	padding and MAC of the second record.

	@security This mode should always be enabled unless explicit compatibility
	with old TLS 1.0 and SSL 3.0 libraries is required.
*/
#define USE_BEAST_WORKAROUND /**< @security ON */

/******************************************************************************/
/**
	Enable certificate chain message "stream" parsing.  This allows single
	certificates to be parsed on-the-fly without having to wait for the entire
	certificate chain to be recieved in the buffer.  This is a memory saving
	feature for the application buffer but will add a small amount of code
	size for the parsing and structure overhead.

	This feature will only save memory if the CERTIFICATE message is the
	only message in the record, and multiple certs are present in the chain.

	@note This features is deprecated and should be enabled only if
	processing long certificate chains with very low memory.
*/
//#define USE_CERT_CHAIN_PARSING /**< @note Setting does not affect security */

/******************************************************************************/
/**
	- USE_TLS versions must 'stack' for compiling purposes
		- must enable TLS if enabling TLS 1.1
		- must enable TLS 1.1 if enabling TLS 1.2
	- Use the DISABLE_TLS_ defines to disallow specific protocols at runtime
		that have been enabled via USE_TLS_.
	- There is no DISABLE_TLS_ for the latest version of the protocol.  If
		you don't want to use that version disable the USE_TLS_ define instead
	The USE_TLS_1_x_AND_ABOVE simplifies this configuration.
	@security To enable SSL3.0, see below.
*/
#define USE_TLS			/**< DO NOT DISABLE @security NIST_MAY */
#define USE_TLS_1_1		/**< DO NOT DISABLE @security NIST_SHALL */
#define USE_TLS_1_2		/**< DO NOT DISABLE @security NIST_SHOULD */
#define DISABLE_SSLV3	/**< DO NOT DISABLE, undef below if required
						@security NIST_SHALL_NOT */

#if defined USE_TLS_1_2_AND_ABOVE
 #define DISABLE_TLS_1_1
 #define DISABLE_TLS_1_0
#elif defined USE_TLS_1_1_AND_ABOVE
 #define DISABLE_TLS_1_0
#elif defined USE_TLS_1_0_AND_ABOVE
 /** @security undef DISABLE_SSLV3 here if required */
#else
 #error Must define USE_TLS_1_x_AND_ABOVE
#endif

#ifdef USE_DTLS
/******************************************************************************/
 /** DTLS definitions */
 #define DTLS_COOKIE_SIZE	16
#endif /* USE_DTLS */

/******************************************************************************/
/**
	Include matrixssl external crypto provider layer headers.
*/

#ifdef USE_ZLIB_COMPRESSION
 #include "zlib.h"
#endif

#if defined(USE_AES_GCM) || defined(USE_AES_CCM) || defined(USE_CHACHA20_POLY1305)
 #define USE_AEAD_CIPHER
#endif

/* PKCS11 is set in crypto. Use all modes of it if enabled */
#define USE_NATIVE_TLS_ALGS
#define USE_NATIVE_TLS_HS_HASH
#define USE_NATIVE_SYMMETRIC

/******************************************************************************/
/**
	Do sanity checks on configuration.
*/
#include "matrixsslCheck.h"

/******************************************************************************/
/*
	Leave this enabled for run-time check of sslKeys_t content when a cipher
	suite is matched.  Disable only if you need to manage key material yourself.
	Always conditional on whether certificate parsing is enabled because it
	looks at members that only exist if certificates have been parsed
*/
#ifdef USE_CERT_PARSE
#define VALIDATE_KEY_MATERIAL
#endif /* USE_CERT_PARSE */

/******************************************************************************/
/**
	SSL protocol and MatrixSSL defines.
	@see https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
*/

/*
	Maximum SSL record size, per specification
*/
#define     SSL_MAX_PLAINTEXT_LEN		0x4000  /* 16KB */
#define     SSL_MAX_RECORD_LEN			SSL_MAX_PLAINTEXT_LEN + 2048
#define     SSL_MAX_BUF_SIZE			SSL_MAX_RECORD_LEN + 0x5
#define		SSL_MAX_DISABLED_CIPHERS	8
/*
	Maximum buffer sizes for static SSL array types
*/
#define SSL_MAX_MAC_SIZE		48 /* SHA384 */
#define SSL_MAX_IV_SIZE			16
#define SSL_MAX_BLOCK_SIZE		16
#define SSL_MAX_SYM_KEY_SIZE	32

/*
	Negative return codes must be between -50 and -69 in the MatrixSSL module
*/
#define     SSL_FULL            -50  /* must call sslRead before decoding */
#define     SSL_PARTIAL         -51 /* more data reqired to parse full msg */
#define     SSL_SEND_RESPONSE   -52  /* decode produced output data */
#define     SSL_PROCESS_DATA    -53  /* succesfully decoded application data */
#define     SSL_ALERT           -54  /* we've decoded an alert */
#define     SSL_FILE_NOT_FOUND  -55  /* File not found */
#define     SSL_MEM_ERROR       PS_MEM_FAIL  /* Memory allocation failure */
#ifdef USE_DTLS
#define     DTLS_MUST_FRAG      -60 /* Message must be fragmented */
#define		DTLS_RETRANSMIT		-61 /* Received a duplicate hs msg from peer */
#endif /* USE_DTLS */

/*
	Magic numbers for handshake header lengths
*/
#define SSL2_HEADER_LEN				2
#define SSL3_HEADER_LEN				5
#define SSL3_HANDSHAKE_HEADER_LEN	4
#ifdef USE_DTLS
 #define DTLS_HEADER_ADD_LEN		8
#endif

#define TLS_CHACHA20_POLY1305_AAD_LEN	13
#define TLS_GCM_AAD_LEN					13
#define TLS_AEAD_SEQNB_LEN				8

#define TLS_GCM_TAG_LEN					16
#define TLS_CHACHA20_POLY1305_TAG_LEN	16
#define TLS_CCM_TAG_LEN					16
#define TLS_CCM8_TAG_LEN				8

#define TLS_AEAD_NONCE_MAXLEN			12 /* Maximum length for an AEAD's nonce */
#define TLS_EXPLICIT_NONCE_LEN			8
#define TLS_CHACHA20_POLY1305_NONCE_LEN	0

#define AEAD_NONCE_LEN(SSL) ((SSL->flags & SSL_FLAGS_NONCE_W) ? TLS_EXPLICIT_NONCE_LEN : 0)
#define AEAD_TAG_LEN(SSL) ((SSL->cipher->flags & CRYPTO_FLAGS_CCM8) ? 8 : 16)

/*
	matrixSslSetSessionOption defines
*/
#define	SSL_OPTION_FULL_HANDSHAKE			1
#ifdef USE_CLIENT_AUTH
#define	SSL_OPTION_DISABLE_CLIENT_AUTH		2
#define	SSL_OPTION_ENABLE_CLIENT_AUTH		3
#endif /* USE_CLIENT_AUTH */
#define SSL_OPTION_DISABLE_REHANDSHAKES		4
#define SSL_OPTION_REENABLE_REHANDSHAKES	5

/*
	SSL Alert levels and descriptions
	This implementation treats all alerts that are not related to
	certificate validation as fatal
*/
#define SSL_ALERT_LEVEL_WARNING             1
#define SSL_ALERT_LEVEL_FATAL               2

#define SSL_ALERT_CLOSE_NOTIFY              0
#define SSL_ALERT_UNEXPECTED_MESSAGE        10
#define SSL_ALERT_BAD_RECORD_MAC            20
#define SSL_ALERT_DECRYPTION_FAILED			21 /* Do not use, per RFC 5246 */
#define SSL_ALERT_RECORD_OVERFLOW			22
#define SSL_ALERT_DECOMPRESSION_FAILURE     30
#define SSL_ALERT_HANDSHAKE_FAILURE         40
#define SSL_ALERT_NO_CERTIFICATE            41
#define SSL_ALERT_BAD_CERTIFICATE           42
#define SSL_ALERT_UNSUPPORTED_CERTIFICATE   43
#define SSL_ALERT_CERTIFICATE_REVOKED       44
#define SSL_ALERT_CERTIFICATE_EXPIRED       45
#define SSL_ALERT_CERTIFICATE_UNKNOWN       46
#define SSL_ALERT_ILLEGAL_PARAMETER         47
#define SSL_ALERT_UNKNOWN_CA				48
#define SSL_ALERT_ACCESS_DENIED				49
#define SSL_ALERT_DECODE_ERROR				50
#define SSL_ALERT_DECRYPT_ERROR				51
#define SSL_ALERT_PROTOCOL_VERSION			70
#define SSL_ALERT_INSUFFICIENT_SECURITY		71
#define SSL_ALERT_INTERNAL_ERROR			80
#define SSL_ALERT_INAPPROPRIATE_FALLBACK	86
#define SSL_ALERT_NO_RENEGOTIATION			100
#define SSL_ALERT_UNSUPPORTED_EXTENSION		110
#define SSL_ALERT_UNRECOGNIZED_NAME			112
#define SSL_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE	113
#define SSL_ALERT_UNKNOWN_PSK_IDENTITY		115
#define SSL_ALERT_NO_APP_PROTOCOL			120

/*
	Use as return code in user validation callback to allow
	anonymous connections to proceed.
	MUST NOT OVERLAP WITH ANY OF THE ALERT CODES ABOVE
*/
#define SSL_ALLOW_ANON_CONNECTION           254

/* Internal values for ssl_t.flags  */
#define	SSL_FLAGS_SERVER		(1<< 0)
#define	SSL_FLAGS_READ_SECURE	(1<< 1)
#define	SSL_FLAGS_WRITE_SECURE	(1<< 2)
#define SSL_FLAGS_RESUMED		(1<< 3)
#define SSL_FLAGS_CLOSED		(1<< 4)
#define SSL_FLAGS_NEED_ENCODE	(1<< 5)
#define SSL_FLAGS_ERROR			(1<< 6)
#define SSL_FLAGS_CLIENT_AUTH	(1<< 7)
#define SSL_FLAGS_ANON_CIPHER	(1<< 8)
#define SSL_FLAGS_FALSE_START	(1<< 9)
#define SSL_FLAGS_SSLV3			(1<<10)
#define SSL_FLAGS_TLS			(1<<11)
#define SSL_FLAGS_TLS_1_0		SSL_FLAGS_TLS	/* For naming consistency */
#define SSL_FLAGS_TLS_1_1		(1<<12)
#define SSL_FLAGS_TLS_1_2		(1<<13)
#define SSL_FLAGS_DTLS			(1<<14)
#define SSL_FLAGS_DHE_WITH_RSA	(1<<15)
#define SSL_FLAGS_DHE_WITH_DSA	(1<<16)
#define SSL_FLAGS_DHE_KEY_EXCH	(1<<17)
#define SSL_FLAGS_PSK_CIPHER	(1<<18)
#define SSL_FLAGS_ECC_CIPHER	(1<<19)
#define SSL_FLAGS_AEAD_W		(1<<20)
#define SSL_FLAGS_AEAD_R		(1<<21)
#define SSL_FLAGS_NONCE_W		(1<<22)
#define SSL_FLAGS_NONCE_R		(1<<23)

#define SSL_FLAGS_INTERCEPTOR	(1<<30)
#define SSL_FLAGS_EAP_FAST		(1<<31)

/* Internal flags for ssl_t.hwflags */
#define SSL_HWFLAGS_HW					(1<<0) /* Use HW for decode/encode */
#define SSL_HWFLAGS_HW_SW				(1<<1) /* Use HW & SW in parallel (debug) */
#define SSL_HWFLAGS_NONBLOCK			(1<<2) /* Use async HW for decode/encode */
#define SSL_HWFLAGS_PENDING_R			(1<<3) /* Non-blocking app record read */
#define SSL_HWFLAGS_PENDING_W			(1<<4) /* Non-blocking app record write */
#define SSL_HWFLAGS_PENDING_FLIGHT_W	(1<<5) /* mid encryptFlight (hshake) */
#define SSL_HWFLAGS_PENDING_PKA_R		(1<<6) /* Non-blocking public key op */
#define SSL_HWFLAGS_PENDING_PKA_W		(1<<7) /* Non-blocking public key op */
#define SSL_HWFLAGS_EAGAIN				(1<<8) /* Not submitted.  Skip hsHash */
#define SSL_HWFLAGS_HW_BAD				(1<<9) /* Bad hardware result,go software */

/* Buffer flags (ssl->bFlags) */
#define BFLAG_CLOSE_AFTER_SENT	(1<<0)
#define BFLAG_HS_COMPLETE		(1<<1)
#define BFLAG_STOP_BEAST		(1<<2)

/*
	Number of bytes server must send before creating a re-handshake credit
*/
#define DEFAULT_RH_CREDITS		1 /* Allow for one rehandshake by default */
#define	BYTES_BEFORE_RH_CREDIT	20 * 1024 * 1024

#ifdef USE_ECC
/* EC flags for sslSessOpts_t */
#define SSL_OPT_SECP192R1	IS_SECP192R1
#define SSL_OPT_SECP224R1	IS_SECP224R1
#define SSL_OPT_SECP256R1	IS_SECP256R1
#define SSL_OPT_SECP384R1	IS_SECP384R1
#define SSL_OPT_SECP521R1	IS_SECP521R1
/* WARNING: Public points on Brainpool curves are not validated */
#define SSL_OPT_BRAIN224R1	IS_BRAIN224R1
#define SSL_OPT_BRAIN256R1	IS_BRAIN256R1
#define SSL_OPT_BRAIN384R1	IS_BRAIN384R1
#define SSL_OPT_BRAIN512R1	IS_BRAIN512R1
#endif

/* Cipher types (internal for CipherSpec_t.type) */
enum PACKED {
	CS_NULL = 0,
	CS_RSA,
	CS_DHE_RSA,
	CS_DH_ANON,
	CS_DHE_PSK,
	CS_PSK,
	CS_ECDHE_ECDSA,
	CS_ECDHE_RSA,
	CS_ECDH_ECDSA,
	CS_ECDH_RSA
};

/*
	These are defines rather than enums because we want to store them as char,
	not int32 (enum size)
*/
#define SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC		(uint8_t)20
#define SSL_RECORD_TYPE_ALERT					(uint8_t)21
#define SSL_RECORD_TYPE_HANDSHAKE				(uint8_t)22
#define SSL_RECORD_TYPE_APPLICATION_DATA		(uint8_t)23
#define SSL_RECORD_TYPE_HANDSHAKE_FIRST_FRAG	(uint8_t)90 /* internal */
#define SSL_RECORD_TYPE_HANDSHAKE_FRAG			(uint8_t)91 /* non-standard types */

#define SSL_HS_HELLO_REQUEST		(uint8_t)0
#define SSL_HS_CLIENT_HELLO			(uint8_t)1
#define SSL_HS_SERVER_HELLO			(uint8_t)2
#define SSL_HS_HELLO_VERIFY_REQUEST	(uint8_t)3
#define SSL_HS_NEW_SESSION_TICKET	(uint8_t)4
#define SSL_HS_CERTIFICATE			(uint8_t)11
#define SSL_HS_SERVER_KEY_EXCHANGE	(uint8_t)12
#define SSL_HS_CERTIFICATE_REQUEST	(uint8_t)13
#define SSL_HS_SERVER_HELLO_DONE	(uint8_t)14
#define SSL_HS_CERTIFICATE_VERIFY	(uint8_t)15
#define SSL_HS_CLIENT_KEY_EXCHANGE	(uint8_t)16
#define SSL_HS_FINISHED				(uint8_t)20
#define SSL_HS_CERTIFICATE_STATUS	(uint8_t)22
#define SSL_HS_ALERT				(uint8_t)252	/* ChangeCipherSuite (internal) */
#define SSL_HS_CCC					(uint8_t)253	/* ChangeCipherSuite (internal) */
#define SSL_HS_NONE					(uint8_t)254	/* No recorded state (internal) */
#define SSL_HS_DONE					(uint8_t)255	/* Handshake complete (internal) */

#define	INIT_ENCRYPT_CIPHER		0
#define INIT_DECRYPT_CIPHER		1

#define HMAC_CREATE	1
#define HMAC_VERIFY 2

#ifdef USE_TLS_1_2
/**
enum {
	none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), sha512(6), (255)
} HashAlgorithm;
enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } SigAlgorithm;
*/
enum PACKED {
	HASH_SIG_MD5 = 1,
	HASH_SIG_SHA1,
	HASH_SIG_SHA256 = 4,
	HASH_SIG_SHA384,
	HASH_SIG_SHA512
};

enum PACKED {
	HASH_SIG_RSA = 1,
	HASH_SIG_ECDSA = 3 /* This 3 is correct for hashSigAlg */
};

/* Internal flag format for algorithms */
enum PACKED {
	/* For RSA we set a bit in the low byte */
	HASH_SIG_MD5_RSA_MASK = 1 << HASH_SIG_MD5,
	HASH_SIG_SHA1_RSA_MASK = 1 << HASH_SIG_SHA1,
	HASH_SIG_SHA256_RSA_MASK = 1 << HASH_SIG_SHA256,
	HASH_SIG_SHA384_RSA_MASK = 1 << HASH_SIG_SHA384,
	HASH_SIG_SHA512_RSA_MASK = 1 << HASH_SIG_SHA512,
	/* For ECDSA we set a bit in the high byte */
	HASH_SIG_SHA1_ECDSA_MASK = 0x100 << HASH_SIG_SHA1,
	HASH_SIG_SHA256_ECDSA_MASK = 0x100 << HASH_SIG_SHA256,
	HASH_SIG_SHA384_ECDSA_MASK = 0x100 << HASH_SIG_SHA384,
	HASH_SIG_SHA512_ECDSA_MASK = 0x100 << HASH_SIG_SHA512,
};

/** Return a unique flag for the given HASH_SIG_ALG. */
static __inline uint16_t HASH_SIG_MASK(uint8_t hash, uint8_t sig)
{
	//TODO - do better validation on hash and sig
	hash = 1 << (hash & 0x7);
	return (sig == HASH_SIG_RSA ? hash : ((uint16_t)hash << 8));
}
#endif /* USE_TLS_1_2 */

/* Additional ssl alert value, indicating no error has ocurred.  */
#define SSL_ALERT_NONE				255	/* No error */

/* SSL/TLS protocol message sizes */
#define SSL_HS_RANDOM_SIZE			32
#define SSL_HS_RSA_PREMASTER_SIZE	48
#ifdef USE_TLS
#define TLS_HS_FINISHED_SIZE	12
#endif /* USE_TLS */

/* Major and minor (not minimum!) version numbers for TLS */
#define SSL2_MAJ_VER		2

#define SSL3_MAJ_VER		3
#define SSL3_MIN_VER		0

#define TLS_MAJ_VER			SSL3_MAJ_VER
#define TLS_MIN_VER			1
#define TLS_1_0_MIN_VER		TLS_MIN_VER
#define TLS_1_1_MIN_VER		2
#define TLS_1_2_MIN_VER		3

/* Based on settings, define the highest TLS version available */
#if defined(USE_TLS_1_2) && !defined(DISABLE_TLS_1_2)
 #define TLS_HIGHEST_MINOR	TLS_1_2_MIN_VER
#elif defined(USE_TLS_1_1) && !defined(DISABLE_TLS_1_1)
 #define TLS_HIGHEST_MINOR	TLS_1_1_MIN_VER
#elif defined(USE_TLS) && !defined(DISABLE_TLS_1_0)
 #define TLS_HIGHEST_MINOR	TLS_1_0_MIN_VER
#elif !defined(DISABLE_SSLV3)
 #define TLS_HIGHEST_MINOR	SSL3_MIN_VER
#else
 #error Unexpected TLS Version
#endif

/* Cipher suite specification IDs, in numerical order. */
#define SSL_NULL_WITH_NULL_NULL					0x0000
#define SSL_RSA_WITH_NULL_MD5					0x0001
#define SSL_RSA_WITH_NULL_SHA					0x0002
#define SSL_RSA_WITH_RC4_128_MD5				0x0004
#define SSL_RSA_WITH_RC4_128_SHA				0x0005
#define TLS_RSA_WITH_IDEA_CBC_SHA				0x0007
#define SSL_RSA_WITH_3DES_EDE_CBC_SHA			0x000A	/* 10 */
#define	SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA		0x0016	/* 22 */
#define SSL_DH_anon_WITH_RC4_128_MD5			0x0018	/* 24 */
#define SSL_DH_anon_WITH_3DES_EDE_CBC_SHA		0x001B	/* 27 */
#define TLS_RSA_WITH_AES_128_CBC_SHA			0x002F	/* 47 */
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA		0x0033	/* 51 */
#define	TLS_DH_anon_WITH_AES_128_CBC_SHA		0x0034	/* 52 */
#define TLS_RSA_WITH_AES_256_CBC_SHA			0x0035	/* 53 */
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA		0x0039	/* 57 */
#define	TLS_DH_anon_WITH_AES_256_CBC_SHA		0x003A	/* 58 */
#define TLS_RSA_WITH_AES_128_CBC_SHA256			0x003C	/* 60 */
#define TLS_RSA_WITH_AES_256_CBC_SHA256			0x003D	/* 61 */
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256		0x0067	/* 103 */
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256		0x006B	/* 107 */
#define TLS_RSA_WITH_SEED_CBC_SHA				0x0096	/* 150 */
#define TLS_PSK_WITH_AES_128_CBC_SHA			0x008C	/* 140 */
#define TLS_PSK_WITH_AES_128_CBC_SHA256			0x00AE	/* 174 */
#define TLS_PSK_WITH_AES_256_CBC_SHA384			0x00AF	/* 175 */
#define TLS_PSK_WITH_AES_256_CBC_SHA			0x008D	/* 141 */
#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA		0x0090	/* 144 */
#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA		0x0091	/* 145 */
#define TLS_RSA_WITH_AES_128_GCM_SHA256			0x009C	/* 156 */
#define TLS_RSA_WITH_AES_256_GCM_SHA384			0x009D	/* 157 */

#define TLS_EMPTY_RENEGOTIATION_INFO_SCSV		0x00FF	/**< @see RFC 5746 */
#define TLS_FALLBACK_SCSV						0x5600	/**< @see RFC 7507 */

#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA		0xC004	/* 49156 */
#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA		0xC005	/* 49157 */
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA	0xC009	/* 49161 */
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA	0xC00A  /* 49162 */
#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA		0xC012	/* 49170 */
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA		0xC013	/* 49171 */
#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA		0xC014	/* 49172 */
#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA		0xC00E	/* 49166 */
#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA		0xC00F	/* 49167 */
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023	/* 49187 */
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024	/* 49188 */
#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256  0xC025	/* 49189 */
#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384  0xC026	/* 49190 */
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256	0xC027	/* 49191 */
#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384	0xC028	/* 49192 */
#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256	0xC029	/* 49193 */
#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384	0xC02A	/* 49194 */
#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B	/* 49195 */
#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C	/* 49196 */
#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256	0xC02D	/* 49197 */
#define TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384	0xC02E	/* 49198 */
#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256	0xC02F	/* 49199 */
#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384	0xC030	/* 49200 */
#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256	0xC031	/* 49201 */
#define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384	0xC032	/* 49202 */
#ifdef CHACHA20POLY1305_IETF
/* Defined in https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305 */
#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256		0xCCA8 /* 52392 */
#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256	0xCCA9	/* 52393 */
#else
/* Defined in https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305 */
#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 	0xCC13 /* 52243 */
#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256	0xCC14	/* 52244 */
#endif

/*
	Supported HELLO extensions
	Extension status stored by bitfield in ssl_t.extFlags
	@see https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
*/
#define EXT_SNI								 0
#define EXT_MAX_FRAGMENT_LEN				 1
#define EXT_TRUSTED_CA_KEYS					 3
#define EXT_TRUNCATED_HMAC					 4
#define EXT_STATUS_REQUEST					 5 /* TODO: rm interceptor dup */
#define EXT_ELLIPTIC_CURVE					10	/* Client-send only */
#define EXT_ELLIPTIC_POINTS					11
#define EXT_SIGNATURE_ALGORITHMS			13
#define EXT_ALPN							16
#define EXT_EXTENDED_MASTER_SECRET			23
#define EXT_SESSION_TICKET					35
#define EXT_RENEGOTIATION_INFO				0xFF01

/* How large the ALPN extension arrary is.  Number of protos client can talk */
#define MAX_PROTO_EXT					8

/*
	Maximum key block size for any defined cipher
	This must be validated if new ciphers are added
	Value is largest total among all cipher suites for
		2*macSize + 2*keySize + 2*ivSize
	Rounded up to nearest PRF block length. We aren't really
		rounding, but just adding another block length for simplicity.
*/
#ifdef USE_TLS_1_2
#define SSL_MAX_KEY_BLOCK_SIZE		((2 * 48) + (2 * 32) + (2 * 16) + \
										SHA256_HASH_SIZE)
#else
#define SSL_MAX_KEY_BLOCK_SIZE		((2 * 48) + (2 * 32) + (2 * 16) + \
										SHA1_HASH_SIZE)
#endif

/*
	Master secret is 48 bytes, sessionId is 32 bytes max
*/
#define		SSL_HS_MASTER_SIZE		48
#define		SSL_MAX_SESSION_ID_SIZE	32

/*
	TLS implementations supporting these ciphersuites MUST support
	arbitrary PSK identities up to 128 octets in length, and arbitrary
	PSKs up to 64 octets in length.  Supporting longer identities and
	keys is RECOMMENDED.
*/
#define SSL_PSK_MAX_KEY_SIZE	64 /* Must be < 256 due to 'idLen' */
#define SSL_PSK_MAX_ID_SIZE		128 /* Must be < 256 due to 'idLen' */
#define SSL_PSK_MAX_HINT_SIZE	32 /* ServerKeyExchange hint is non-standard */

#ifdef USE_DTLS
#define	MAX_FRAGMENTS	8
#define PS_MIN_PMTU		256

typedef struct {
	int32	offset;
	int32	fragLen;
	char	*hsHeader;
} dtlsFragHdr_t;

#ifndef USE_DTLS_DEBUG_TRACE
#define psTraceDtls(x)
#define psTraceIntDtls(x, y)
#define psTraceStrDtls(x, y)
#else
#define psTraceDtls(x) _psTrace(x)
#define psTraceIntDtls(x, y) _psTraceInt(x, y)
#define psTraceStrDtls(x, y) _psTraceStr(x, y)
#endif /* USE_DTLS_DEBUG_TRACE */

#endif /* USE_DTLS */


#ifndef USE_SSL_HANDSHAKE_MSG_TRACE
#define psTraceHs(x)
#define psTraceStrHs(x, y)
#else
#define psTraceHs(x) _psTrace(x)
#define psTraceStrHs(x, y) _psTraceStr(x, y)
#endif /* USE_SSL_HANDSHAKE_MSG_TRACE */

#ifndef USE_SSL_INFORMATIONAL_TRACE
#define psTraceInfo(x)
#define psTraceStrInfo(x, y)
#define psTraceIntInfo(x, y)
#else
#define psTraceInfo(x) _psTrace(x)
#define psTraceStrInfo(x, y) _psTraceStr(x, y)
#define psTraceIntInfo(x, y) _psTraceInt(x, y)
#endif /* USE_SSL_INFORMATIONAL_TRACE */

/******************************************************************************/

struct ssl;

typedef psBuf_t	sslBuf_t;

/******************************************************************************/

#ifdef USE_PSK_CIPHER_SUITE
typedef struct psPsk {
	unsigned char	*pskKey;
	uint8_t			pskLen;
	unsigned char	*pskId;
	uint8_t			pskIdLen;
	struct psPsk	*next;
} psPsk_t;
#endif /* USE_PSK_CIPHER_SUITE */

typedef	int32_t (*pskCb_t)(struct ssl *ssl,
				const unsigned char pskId[SSL_PSK_MAX_ID_SIZE], uint8_t pskIdLen,
				unsigned char *psk[SSL_PSK_MAX_KEY_SIZE], uint8_t *pskLen);

#if defined(USE_SERVER_SIDE_SSL) && defined(USE_STATELESS_SESSION_TICKETS)
typedef int32 (*sslSessTicketCb_t)(void *keys, unsigned char[16], short);

typedef struct sessTicketKey {
	unsigned char			name[16];
	unsigned char			symkey[32];
	unsigned char			hashkey[32];
	short					nameLen, symkeyLen, hashkeyLen, inUse;
	struct sessTicketKey	*next;
} psSessionTicketKeys_t;
#endif

/******************************************************************************/
/*
	TLS authentication keys structures
*/
#if defined(USE_ECC) || defined(REQUIRE_DH_PARAMS)
#define ECC_EPHEMERAL_CACHE_SECONDS	(2 * 60 * 60) /**< Max lifetime in sec */
#ifdef NO_ECC_EPHEMERAL_CACHE
#define ECC_EPHEMERAL_CACHE_USAGE	0       /**< Cache not used */
#else
#define ECC_EPHEMERAL_CACHE_USAGE	1000	/**< Maximum use count of key */
#endif
typedef struct {
#ifdef USE_MULTITHREADING
	psMutex_t		lock;
#endif
#ifdef USE_ECC
	psEccKey_t		eccPrivKey; /**< Cached ephemeral key */
	psEccKey_t		eccPubKey; /**< Cached remote ephemeral pub key */
	psTime_t		eccPrivKeyTime;	/**< Time key was generated */
	uint16_t		eccPrivKeyUse;	/**< Use count */
	uint16_t		eccPubKeyCurveId;	/**< Curve the point is on */
	unsigned char	eccPubKeyRaw[132];	/**< Max size of secp521r1 */
#endif
#ifdef REQUIRE_DH_PARAMS
#endif
} ephemeralKeyCache_t;
#endif /* defined(USE_ECC) || defined(REQUIRE_DH_PARAMS) */

typedef struct {
	psPool_t		*pool;
#if defined(USE_SERVER_SIDE_SSL) || defined(USE_CLIENT_AUTH)
	//TODO - verify that the public part of the privKey is equal to the pubkey
	//in the cert
	psPubKey_t		privKey;
	psX509Cert_t	*cert;
#endif /* USE_SERVER_SIDE_SSL || USE_CLIENT_AUTH */
#if defined(USE_CLIENT_SIDE_SSL) || defined(USE_CLIENT_AUTH)
	psX509Cert_t	*CAcerts;
#endif /* USE_CLIENT_SIDE_SSL || USE_CLIENT_AUTH */
#ifdef REQUIRE_DH_PARAMS
	psDhParams_t	dhParams;
#endif /* REQUIRE_DH_PARAMS */
#ifdef USE_PSK_CIPHER_SUITE
	psPsk_t			*pskKeys;
#endif /* USE_PSK_CIPHER_SUITE */
#if defined(USE_SERVER_SIDE_SSL) && defined(USE_STATELESS_SESSION_TICKETS)
	psSessionTicketKeys_t	*sessTickets;
	sslSessTicketCb_t		ticket_cb;
#endif
#if defined(USE_OCSP) && defined(USE_SERVER_SIDE_SSL)
	unsigned char	*OCSPResponseBuf;
	uint16_t		OCSPResponseBufLen;
#endif
	void			*poolUserPtr; /* Data that will be given to psOpenPool
									for any operations involving these keys */
#if defined(USE_ECC) || defined(REQUIRE_DH_PARAMS)
	ephemeralKeyCache_t	cache;
#endif
} sslKeys_t;

/******************************************************************************/
/* Type to pass optional features to NewSession calls */
typedef struct {
	short		ticketResumption; /* Client: 1 to use.  Server N/A */
	short		maxFragLen; /* Client: 512 etc..  Server: -1 to disable */
	short		truncHmac; /* Client: 1 to use.  Server: -1 to disable */
	short		extendedMasterSecret; /* On by default.  -1 to disable */
	short		trustedCAindication; /* Client: 1 to use */
	short		fallbackScsv; /* Client: 1 to use */
#ifdef USE_OCSP
	short		OCSPstapling; /* Client: 1 to send status_request */
#endif	
#ifdef USE_ECC
	int32		ecFlags; /* Elliptic curve set (SSL_OPT_SECP192R1 etc.) */
#endif
	int32		versionFlag; /* The SSL_FLAGS_TLS_ version (+ DTLS flag here) */
	void		*userPtr; /* Initial value of ssl->userPtr during NewSession */
	void		*memAllocPtr; /* Will be passed to psOpenPool for each call
								related to this session */
	psPool_t	*bufferPool; /* Optional mem pool for inbuf and outbuf */
} sslSessOpts_t;

typedef struct {
    unsigned short  keyType;
    unsigned short	hashAlg;
	unsigned short	curveFlags;
	unsigned short	dhParamsRequired;
	char			*serverName;
} sslPubkeyId_t;

typedef sslKeys_t *(*pubkeyCb_t)(struct ssl *ssl, const sslPubkeyId_t *keyId);
typedef int32_t (*sslExtCb_t)(struct ssl *ssl, uint16_t extType, uint8_t extLen,
				void *e);
typedef int32_t (*sslCertCb_t)(struct ssl *ssl, psX509Cert_t *cert, int32_t alert);

#ifdef USE_OCSP
typedef int32_t (*ocspCb_t)(struct ssl *ssl, mOCSPResponse_t *response,
		psX509Cert_t *cert, int32_t status);
#endif

/******************************************************************************/
/*
	SSL record and session structures
*/
typedef struct {
	unsigned short	len;
	unsigned char	majVer;
	unsigned char	minVer;
#ifdef USE_DTLS
	unsigned char	epoch[2];	/* incoming epoch number */
	unsigned char	rsn[6];		/* incoming record sequence number */
#endif /* USE_DTLS */
#ifdef USE_CERT_CHAIN_PARSING
	unsigned short	hsBytesHashed;
	unsigned short	hsBytesParsed;
	unsigned short	trueLen;
	unsigned char	partial;
	unsigned char	certPad;
#endif
	unsigned char	type;
	unsigned char	pad[3];		/* Padding for 64 bit compat */
} sslRec_t;

typedef struct {
	unsigned char	clientRandom[SSL_HS_RANDOM_SIZE];	/* From ClientHello */
	unsigned char	serverRandom[SSL_HS_RANDOM_SIZE];	/* From ServerHello */
	unsigned char	masterSecret[SSL_HS_MASTER_SIZE];
	unsigned char	*premaster;							/* variable size */
	uint16_t		premasterSize;

	unsigned char	keyBlock[SSL_MAX_KEY_BLOCK_SIZE];	/* Storage for 'ptr' */
	unsigned char	*wMACptr;
	unsigned char	*rMACptr;
	unsigned char	*wKeyptr;
	unsigned char	*rKeyptr;

	/*	All maximum sizes for current cipher suites */
	unsigned char	writeMAC[SSL_MAX_MAC_SIZE];
	unsigned char	readMAC[SSL_MAX_MAC_SIZE];
	unsigned char	writeKey[SSL_MAX_SYM_KEY_SIZE];
	unsigned char	readKey[SSL_MAX_SYM_KEY_SIZE];
	unsigned char	*wIVptr;
	unsigned char	*rIVptr;
	unsigned char	writeIV[SSL_MAX_IV_SIZE];
	unsigned char	readIV[SSL_MAX_IV_SIZE];

	unsigned char	seq[8];
	unsigned char	remSeq[8];

	pskCb_t			pskCb;

#ifndef USE_ONLY_PSK_CIPHER_SUITE
	pubkeyCb_t		pubkeyCb;
#if defined(USE_CLIENT_SIDE_SSL) || defined(USE_CLIENT_AUTH)
	psX509Cert_t	*cert;
	sslCertCb_t		validateCert;
#endif /* USE_CLIENT_SIDE_SSL || USE_CLIENT_AUTH */
#endif /* USE_ONLY_PSK_CIPHER_SUITE */

#ifdef USE_CLIENT_SIDE_SSL
	int32				certMatch;
#endif /* USE_CLIENT_SIDE_SSL */

	psCipherContext_t	encryptCtx;
	psCipherContext_t	decryptCtx;

#ifndef USE_ONLY_TLS_1_2
	psMd5Sha1_t			msgHashMd5Sha1;
#endif

#ifdef USE_TLS_1_2
	psSha256_t			msgHashSha256;

#ifdef USE_SHA1
	psSha1_t			msgHashSha1;
#endif
#ifdef USE_SHA384
	psSha384_t			msgHashSha384;
#endif
#ifdef USE_SHA512
	psSha512_t			msgHashSha512;
#endif
#endif /* USE_TLS_1_2 */

#if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH)
	unsigned char		sha1Snapshot[SHA1_HASH_SIZE];
	unsigned char		sha384Snapshot[SHA384_HASH_SIZE]; /* HW crypto uses
															outside TLS 1.2 */
	unsigned char		sha512Snapshot[SHA512_HASH_SIZE];
#endif

#if defined(USE_PSK_CIPHER_SUITE) && defined(USE_CLIENT_SIDE_SSL)
	unsigned char		*hint;
	uint8_t				hintLen;
#endif /* USE_PSK_CIPHER_SUITE && USE_CLIENT_SIDE_SSL */

#ifdef REQUIRE_DH_PARAMS
	unsigned char		*dhP;			/* prime/modulus */
	unsigned char		*dhG;			/* base/generator */
	uint16_t			dhPLen;
	uint16_t			dhGLen;
	psDhKey_t			*dhKeyPub;		/* remote key */
	psDhKey_t			*dhKeyPriv;		/* local key */
	psPool_t			*dhKeyPool;		/* handshake-scope pool for clients */
#endif

#ifdef USE_ECC_CIPHER_SUITE
	psEccKey_t			*eccKeyPriv; /* local key */
	psEccKey_t			*eccKeyPub; /* remote key */
	psPool_t			*eccDhKeyPool; /* handshake-scope pool for clients */
#endif

	int32				anon;
} sslSec_t;

typedef struct {
	uint16_t		ident;	/* Official cipher ID */
	uint16_t		type;	/* Key exchange method */
	uint32_t		flags;	/* from CRYPTO_FLAGS_* */
	uint8_t 		macSize;
	uint8_t			keySize;
	uint8_t			ivSize;
	uint8_t			blockSize;
	/* Init function */
	int32 (*init)(sslSec_t *sec, int32 type, uint32 keysize);
	/* Cipher functions */
	int32 (*encrypt)(void *ssl, unsigned char *in,
		unsigned char *out, uint32 len);
	int32 (*decrypt)(void *ssl, unsigned char *in,
		unsigned char *out, uint32 len);
	int32 (*generateMac)(void *ssl, unsigned char type, unsigned char *data,
		uint32 len, unsigned char *mac);
	int32 (*verifyMac)(void *ssl, unsigned char type, unsigned char *data,
		uint32 len, unsigned char *mac);
} sslCipherSpec_t;


#ifdef USE_STATELESS_SESSION_TICKETS
enum sessionTicketState_e {
	SESS_TICKET_STATE_INIT = 0,
	SESS_TICKET_STATE_SENT_EMPTY,
	SESS_TICKET_STATE_SENT_TICKET,
	SESS_TICKET_STATE_RECVD_EXT,
	SESS_TICKET_STATE_IN_LIMBO,
	SESS_TICKET_STATE_USING_TICKET
};
#endif

/* Used by user code to store cached session info after the ssl_t is closed */
typedef struct {
	psPool_t		*pool;
	unsigned char	id[SSL_MAX_SESSION_ID_SIZE];
	unsigned char	masterSecret[SSL_HS_MASTER_SIZE];
	uint32			cipherId;
#ifdef USE_STATELESS_SESSION_TICKETS
	unsigned char	*sessionTicket;		/* Duplicated into 'pool' */
	uint16			sessionTicketState;	/* Not an enum to ensure 2 bytes */
	uint16			sessionTicketLen;	/* Max 32767 */
	uint32			sessionTicketLifetimeHint;
#endif
} sslSessionId_t;

/* Used internally by the session cache table to store session parameters */
typedef struct {
	unsigned char	id[SSL_MAX_SESSION_ID_SIZE];
	unsigned char	masterSecret[SSL_HS_MASTER_SIZE];
	const sslCipherSpec_t	*cipher;
	unsigned char	majVer;
	unsigned char	minVer;
	short			extendedMasterSecret; /* was the extension used? */
	psTime_t		startTime;
	int32			inUse;
	DLListEntry		chronList;
} sslSessionEntry_t;

/* Used by user code to define custom hello extensions */
typedef struct tlsHelloExt {
	psPool_t			*pool;
	int32				extType;
	uint32				extLen;
	unsigned char		*extData;
	struct tlsHelloExt	*next;
} tlsExtension_t;

/* Hold the info needed to perform a public key operation for flight writes
	until the very end.  This is an architectural change that was added to aid
	the	integration of non-blocking hardware acceleration */
enum {
	PKA_AFTER_RSA_SIG_GEN_ELEMENT = 1,
	PKA_AFTER_RSA_SIG_GEN,
	PKA_AFTER_ECDSA_SIG_GEN,
	PKA_AFTER_RSA_ENCRYPT, /* standard RSA CKE operation */
	PKA_AFTER_ECDH_KEY_GEN, /* ECDH CKE operation. makeKey */
	PKA_AFTER_ECDH_SECRET_GEN, /* GenSecret */
	PKA_AFTER_ECDH_SECRET_GEN_DONE, /* Control for single-pass op */
	PKA_AFTER_DH_KEY_GEN /* DH CKE operation */
};

typedef struct {
	unsigned char	*inbuf; /* allocated to handshake pool */
	unsigned char	*outbuf;
	void			*data; /* hw pkiData */
	uint16_t		inlen;
	uint16_t		type; /* one of PKA_AFTER_* */
	uint16_t		user; /* user size */
	psPool_t		*pool;
} pkaAfter_t;

typedef struct nextMsgInFlight {
	unsigned char	*start;
	unsigned char	*seqDelay;
	int32			len;
	int32			type;
	int32			messageSize;
	int32			padLen;
	int32			hsMsg;
#ifdef USE_DTLS
	int32			fragCount;
#endif
	struct nextMsgInFlight	*next;
} flightEncode_t;

struct ssl {
	sslRec_t		rec;			/* Current SSL record information*/

	sslSec_t		sec;			/* Security structure */

//TODO
//	tlsSessionKeys_t	skeys;

	sslKeys_t		*keys;			/* SSL public and private keys */

	pkaAfter_t		pkaAfter[2];	/* Cli-side cli-auth = two PKA in flight */
	flightEncode_t	*flightEncode;
	unsigned char	*delayHsHash;
	unsigned char	*seqDelay;	/* tmp until flightEncode_t is built */

	psPool_t		*bufferPool; /* If user passed options.bufferPool to
									NewSession, this is inbuf and outbuf pool */
	psPool_t		*sPool;			/* SSL session pool */
	psPool_t		*hsPool;		/* Full session handshake pool */
	psPool_t		*flightPool;	/* Small but handy */

	unsigned char	sessionIdLen;
	unsigned char	sessionId[SSL_MAX_SESSION_ID_SIZE];
	sslSessionId_t	*sid;
	char			*expectedName;	/* Clients: The expected cert subject name
											passed to NewClient Session 
									   Servers: Holds SNI value */
#ifdef USE_SERVER_SIDE_SSL
	uint16			disabledCiphers[SSL_MAX_DISABLED_CIPHERS];
	void			(*sni_cb)(void *ssl, char *hostname, int32 hostnameLen,
						sslKeys_t **newKeys);
#ifdef USE_ALPN
	void			(*srv_alpn_cb)(void *ssl, short protoCount,
						char *proto[MAX_PROTO_EXT],
						int32 protoLen[MAX_PROTO_EXT], int32 *index);
	char			*alpn; /* proto user has agreed to use */
	int32			alpnLen;
#endif /* USE_ALPN */
#endif /* USE_SERVER_SIDE_SSL */
#ifdef USE_CLIENT_SIDE_SSL
	/* Just to handle corner case of app data tacked on HELLO_REQUEST */
	int32			anonBk;
	int32			flagsBk;
	uint32			bFlagsBk;
#endif /* USE_CLIENT_SIDE_SSL */

	unsigned char	*inbuf;
	unsigned char	*outbuf;
	int32			inlen;		/* Bytes unprocessed in inbuf */
	int32			outlen;		/* Bytes unsent in outbuf */
	int32			insize;		/* Total allocated size of inbuf */
	int32			outsize;	/* Total allocated size of outbuf */
	uint32			bFlags;		/* Buffer related flags */

	int32			maxPtFrag;	/* 16K by default - SSL_MAX_PLAINTEXT_LEN */
	unsigned char	*fragMessage; /* holds the constructed fragmented message */
	uint32			fragIndex;	/* How much data has been written to msg */
	uint32			fragTotal;	/* Total length of fragmented message */

	/* Pointer to the negotiated cipher information */
	const sslCipherSpec_t	*cipher;

	/* 	Symmetric cipher callbacks

		We duplicate these here from 'cipher' because we need to set the
		various callbacks at different times in the handshake protocol
		Also, there are 64 bit alignment issues in using the function pointers
		within 'cipher' directly
	*/
	int32 (*encrypt)(void *ctx, unsigned char *in,
		unsigned char *out, uint32 len);
	int32 (*decrypt)(void *ctx, unsigned char *in,
		unsigned char *out, uint32 len);
	/* Message Authentication Codes */
	int32 (*generateMac)(void *ssl, unsigned char type, unsigned char *data,
		uint32 len, unsigned char *mac);
	int32 (*verifyMac)(void *ssl, unsigned char type, unsigned char *data,
		uint32 len, unsigned char *mac);

	/* Current encryption/decryption parameters */
	unsigned char	enMacSize;
	unsigned char	nativeEnMacSize; /* truncated hmac support */
	unsigned char	enIvSize;
	unsigned char	enBlockSize;
	unsigned char	deMacSize;
	unsigned char	nativeDeMacSize; /* truncated hmac support */
	unsigned char	deIvSize;
	unsigned char	deBlockSize;

	uint32_t		flags;			/* SSL_FLAGS_ */
	int32_t			err;			/* SSL errno of last api call */
	int32_t			ignoredMessageCount;

	uint8_t			hsState;		/* Next expected SSL_HS_ message type */
	uint8_t			decState;		/* Most recent encoded SSL_HS_ message */
	uint8_t			encState;		/* Most recent decoded SSL_HS_ message */
	uint8_t			reqMajVer;
	uint8_t			reqMinVer;
	uint8_t			majVer;
	uint8_t			minVer;
	uint8_t			outRecType;

#ifdef ENABLE_SECURE_REHANDSHAKES
	unsigned char	myVerifyData[SHA384_HASH_SIZE]; /*SSLv3 max*/
	unsigned char	peerVerifyData[SHA384_HASH_SIZE];
	uint32			myVerifyDataLen;
	uint32			peerVerifyDataLen;
	int32			secureRenegotiationFlag;
#endif /* ENABLE_SECURE_REHANDSHAKES */
#ifdef SSL_REHANDSHAKES_ENABLED
	int32			rehandshakeCount; /* Make this an internal define of 1 */
	int32			rehandshakeBytes; /* Make this an internal define of 10MB */
#endif /* SSL_REHANDSHAKES_ENABLED */

	sslExtCb_t		extCb;
#ifdef USE_ECC
	struct {
		uint32		ecFlags:24;
		uint32		ecCurveId:8;
	} ecInfo;
#endif
#ifdef USE_TLS_1_2
	uint16_t		hashSigAlg;
#endif

#ifdef USE_DTLS
#ifdef USE_SERVER_SIDE_SSL
	unsigned char	srvCookie[DTLS_COOKIE_SIZE]; /* server can avoid allocs */
#endif
#ifdef USE_CLIENT_SIDE_SSL
	unsigned char	*cookie;	/* hello_verify_request cookie */
	int32			cookieLen;	/* cookie length */
	int32			haveCookie;	/* boolean for cookie existence */
#endif
	unsigned char	*helloExt;	/* need to save the original client hello ext */
	int32			helloExtLen;
	unsigned char	hsSnapshot[SHA512_HASH_SIZE]; /*SSLv3 max*/
	int32			hsSnapshotLen;
	uint16_t		cipherSpec[8]; /* also needed for the cookie client hello */
	uint8_t			cipherSpecLen;
	unsigned char	epoch[2];	/* Current epoch number to send with msg */
	unsigned char	resendEpoch[2];	/* Starting epoch to use for resends */
	unsigned char	expectedEpoch[2];	/* Expected incoming epoch */
	unsigned char	largestEpoch[2]; /* FINISH resends need to incr epoch */
	unsigned char	rsn[6];			/* Last Record Sequence Number sent */
	unsigned char	largestRsn[6];	/* Needed for resends of CCS flight */
	unsigned char	lastRsn[6];	/* Last RSN received (for replay detection) */
	unsigned long	dtlsBitmap; /* Record replay helper */
	int32			parsedCCS;	/* Set between CCS parse and FINISHED parse */
	int32			msn;		/* Current Message Sequence Number to send */
	int32			resendMsn;	/* Starting MSN to use for resends */
	int32			lastMsn;	/* Last MSN successfully parsed from peer */
	int32			pmtu;		/* path maximum trasmission unit */
	int32			retransmit; /* Flag to know not to update handshake hash */
	uint16			flightDone; /* BOOL to flag when entire hs flight sent */
	uint16			appDataExch; /* BOOL to flag if in application data mode */
	int32			fragMsn;	/* fragment MSN */
	dtlsFragHdr_t	fragHeaders[MAX_FRAGMENTS]; /* header storage for hash */
	int32 (*oencrypt)(void *ctx, unsigned char *in,
					 unsigned char *out, uint32 len);
	int32 (*ogenerateMac)(void *ssl, unsigned char type, unsigned char *data,
						 uint32 len, unsigned char *mac);
	unsigned char	oenMacSize;
	unsigned char	oenNativeHmacSize;
	unsigned char	oenIvSize;
	unsigned char	oenBlockSize;
	unsigned char	owriteIV[16]; /* GCM uses this in the nonce */
	unsigned char	owriteMAC[SSL_MAX_MAC_SIZE];
	psCipherContext_t	oencryptCtx;
#ifdef ENABLE_SECURE_REHANDSHAKES
	unsigned char	omyVerifyData[SHA384_HASH_SIZE];
	uint32			omyVerifyDataLen;
#endif /* ENABLE_SECURE_REHANDSHAKES */
	uint32			ckeSize;
	unsigned char	*ckeMsg;
	unsigned char	*certVerifyMsg;
	int32			certVerifyMsgLen;
	int				ecdsaSizeChange; /* retransmits for ECDSA sig */
#endif /* USE_DTLS */

#ifdef USE_ZLIB_COMPRESSION
	int32			compression;
	z_stream		inflate;
	z_stream		deflate;
	unsigned char	*zlibBuffer; /* scratch pad for inflate/deflate data */
#endif

	struct {
#ifdef USE_CLIENT_SIDE_SSL
		/* Did the client request the extension? */
		uint32		req_sni: 1;
		uint32		req_max_fragment_len: 1;
		uint32		req_truncated_hmac: 1;
		uint32		req_extended_master_secret: 1;
		uint32		req_elliptic_curve: 1;
		uint32		req_elliptic_points: 1;
		uint32		req_signature_algorithms: 1;
		uint32		req_alpn: 1;
		uint32		req_session_ticket: 1;
		uint32		req_renegotiation_info: 1;
		uint32		req_fallback_scsv: 1;
		uint32		req_status_request: 1;
#endif
#ifdef USE_SERVER_SIDE_SSL
		/* Whether the server will deny the extension */
		uint32		deny_truncated_hmac: 1;
		uint32		deny_max_fragment_len: 1;
		uint32		deny_session_ticket: 1;
#endif
		/* Set if the extension was negotiated successfully */
		uint32		sni: 1;
		uint32		truncated_hmac: 1;
		uint32		extended_master_secret: 1;
		uint32		session_id: 1;
		uint32		session_ticket: 1;
		uint32		status_request: 1;	/* received EXT_STATUS_REQUEST */
		uint32		status_request_v2: 1;	/* received EXT_STATUS_REQUEST_V2 */
		uint32		require_extended_master_secret: 1; /* peer may require */
	} extFlags;	/**< Extension flags */

#ifdef USE_MATRIX_OPENSSL_LAYER
	int (*verify_callback)(int alert, psX509Cert_t *data);
#endif
	int32			recordHeadLen;
	int32			hshakeHeadLen;
#ifdef USE_MATRIXSSL_STATS
	void (*statCb)(void *ssl, void *stats_ptr, int32 type, int32 value);
	void *statsPtr;
#endif
	void *memAllocPtr; /* Will be passed to psOpenPool for each call
							related to this session */
	void *userPtr;
};

typedef struct ssl ssl_t;

/******************************************************************************/
/*
	Former public APIS in 1.x and 2.x. Now deprecated in 3.x
	These functions are still heavily used internally, just no longer publically
	supported.
 */
extern int32 matrixSslDecode(ssl_t *ssl, unsigned char **buf, uint32 *len,
						uint32 size, uint32 *remaining, uint32 *requiredLen,
						int32 *error, unsigned char *alertLevel,
						unsigned char *alertDescription);
extern int32 matrixSslEncode(ssl_t *ssl, unsigned char *buf, uint32 size,
						unsigned char *ptBuf, uint32 *len);
extern int32	matrixSslGetEncodedSize(ssl_t *ssl, uint32 len);
extern void		matrixSslSetCertValidator(ssl_t *ssl, sslCertCb_t certValidator);
extern int32	matrixSslNewSession(ssl_t **ssl, const sslKeys_t *keys,
					sslSessionId_t *session, sslSessOpts_t *options);
extern void		matrixSslSetSessionOption(ssl_t *ssl, int32 option,	void *arg);
extern int32_t	matrixSslHandshakeIsComplete(const ssl_t *ssl);

/* This used to be prefixed with 'matrix' */
extern int32	sslEncodeClosureAlert(ssl_t *ssl, sslBuf_t *out,
									  uint32 *reqLen);

extern int32 matrixSslEncodeHelloRequest(ssl_t *ssl, sslBuf_t *out,
				uint32 *reqLen);
extern int32_t matrixSslEncodeClientHello(ssl_t *ssl, sslBuf_t *out,
				const uint16_t cipherSpec[], uint8_t cipherSpecLen,
				uint32 *requiredLen, tlsExtension_t *userExt,
				sslSessOpts_t *options);

#ifdef USE_CLIENT_SIDE_SSL
extern int32	matrixSslGetSessionId(ssl_t *ssl, sslSessionId_t *sessionId);
#endif /* USE_CLIENT_SIDE_SSL */

#ifdef USE_SSL_INFORMATIONAL_TRACE
extern void matrixSslPrintHSDetails(ssl_t *ssl);
#endif /* USE_SSL_INFORMATIONAL_TRACE */

#ifdef SSL_REHANDSHAKES_ENABLED
PSPUBLIC int32 matrixSslGetRehandshakeCredits(ssl_t *ssl);
PSPUBLIC void matrixSslAddRehandshakeCredits(ssl_t *ssl, int32 credits);
#endif

#ifdef USE_ZLIB_COMPRESSION
PSPUBLIC int32 matrixSslIsSessionCompressionOn(ssl_t *ssl);
#endif

/******************************************************************************/
/*
	MatrixSSL internal cert functions
*/

#ifndef USE_ONLY_PSK_CIPHER_SUITE
extern int32 matrixValidateCerts(psPool_t *pool, psX509Cert_t *subjectCerts,
				psX509Cert_t *issuerCerts, char *expectedName,
				psX509Cert_t **foundIssuer, void *pkiData, void *userPoolPtr);
extern int32 matrixUserCertValidator(ssl_t *ssl, int32 alert,
				 psX509Cert_t *subjectCert, sslCertCb_t certCb);
#endif /* USE_ONLY_PSK_CIPHER_SUITE */


/******************************************************************************/
/*
	handshakeDecode.c and extensionDecode.c
*/
#ifdef USE_SERVER_SIDE_SSL
extern int32 parseClientHello(ssl_t *ssl, unsigned char **cp,
				unsigned char *end);
extern int32 parseClientHelloExtensions(ssl_t *ssl, unsigned char **cp,
				unsigned short len);
extern int32 parseClientKeyExchange(ssl_t *ssl, int32 hsLen, unsigned char **cp,
				unsigned char *end);
#ifndef USE_ONLY_PSK_CIPHER_SUITE
#ifdef USE_CLIENT_AUTH
extern int32 parseCertificateVerify(ssl_t *ssl,
				unsigned char hsMsgHash[SHA512_HASH_SIZE], unsigned char **cp,
				unsigned char *end);
#endif /* USE_CLIENT_AUTH */
#endif /* !USE_ONLY_PSK_CIPHER_SUITE */
#endif /* USE_SERVER_SIDE_SSL */

#ifdef USE_CLIENT_SIDE_SSL
extern int32 parseServerHello(ssl_t *ssl, int32 hsLen, unsigned char **cp,
				unsigned char *end);
extern int32 parseServerHelloExtensions(ssl_t *ssl, int32 hsLen,
				unsigned char *extData,	unsigned char **cp,
				unsigned short len);
extern int32 parseServerHelloDone(ssl_t *ssl, int32 hsLen, unsigned char **cp,
				unsigned char *end);
extern int32 parseServerKeyExchange(ssl_t *ssl,
				unsigned char hsMsgHash[SHA384_HASH_SIZE],
				unsigned char **cp,	unsigned char *end);
#ifdef USE_OCSP
extern int32 parseCertificateStatus(ssl_t *ssl, int32 hsLen, unsigned char **cp,
				unsigned char *end);
#endif
#ifndef USE_ONLY_PSK_CIPHER_SUITE
extern int32 parseCertificateRequest(ssl_t *ssl, int32 hsLen,
				unsigned char **cp,	unsigned char *end);
#endif
#endif /* USE_CLIENT_SIDE_SSL */

#ifndef USE_ONLY_PSK_CIPHER_SUITE
#if defined(USE_CLIENT_SIDE_SSL) || defined(USE_CLIENT_AUTH)
extern int32 parseCertificate(ssl_t *ssl, unsigned char **cp,
				unsigned char *end);
#endif
#endif

extern int32 parseFinished(ssl_t *ssl, int32 hsLen,
				unsigned char hsMsgHash[SHA384_HASH_SIZE], unsigned char **cp,
				unsigned char *end);

/******************************************************************************/
/*
	sslEncode.c and sslDecode.c
*/
extern int32 psWriteRecordInfo(ssl_t *ssl, unsigned char type, int32 len,
							 unsigned char *c, int32 hsType);
extern int32 psWriteHandshakeHeader(ssl_t *ssl, unsigned char type, int32 len,
								int32 seq, int32 fragOffset, int32 fragLen,
								unsigned char *c);
extern int32 sslEncodeResponse(ssl_t *ssl, psBuf_t *out, uint32 *requiredLen);
extern int32 sslActivateReadCipher(ssl_t *ssl);
extern int32 sslActivateWriteCipher(ssl_t *ssl);
extern int32_t sslUpdateHSHash(ssl_t *ssl, const unsigned char *in, uint16_t len);
extern int32 sslInitHSHash(ssl_t *ssl);
extern int32 sslSnapshotHSHash(ssl_t *ssl, unsigned char *out, int32 senderFlag);
extern int32 sslWritePad(unsigned char *p, unsigned char padLen);
extern int32 sslCreateKeys(ssl_t *ssl);
extern void sslResetContext(ssl_t *ssl);
extern void clearPkaAfter(ssl_t *ssl);
extern pkaAfter_t *getPkaAfter(ssl_t *ssl);
extern void freePkaAfter(ssl_t *ssl);
extern void clearFlightList(ssl_t *ssl);

#ifdef USE_SERVER_SIDE_SSL
extern int32 matrixRegisterSession(ssl_t *ssl);
extern int32 matrixResumeSession(ssl_t *ssl);
extern int32 matrixClearSession(ssl_t *ssl, int32 remove);
extern int32 matrixUpdateSession(ssl_t *ssl);
extern int32 matrixServerSetKeysSNI(ssl_t *ssl, char *host, int32 hostLen);

#ifdef USE_STATELESS_SESSION_TICKETS
extern int32 matrixSessionTicketLen(void);
extern int32 matrixCreateSessionTicket(ssl_t *ssl, unsigned char *out,
				int32 *outLen);
extern int32 matrixUnlockSessionTicket(ssl_t *ssl, unsigned char *in,
				int32 inLen);
extern int32 matrixSessionTicketLen(void);
#endif
#endif /* USE_SERVER_SIDE_SSL */

#ifdef USE_DTLS
extern int32 dtlsChkReplayWindow(ssl_t *ssl, unsigned char *seq64);
extern int32 dtlsWriteCertificate(ssl_t *ssl, int32 certLen,
								  int32 lsize, unsigned char *c);
extern int32 dtlsWriteCertificateRequest(psPool_t *pool, ssl_t *ssl, int32 certLen,
						   int32 certCount, int32 sigHashLen, unsigned char *c);
extern int32 dtlsComputeCookie(ssl_t *ssl, unsigned char *helloBytes,
							   int32 helloLen);
extern void dtlsInitFrag(ssl_t *ssl);
extern int32 dtlsSeenFrag(ssl_t *ssl, int32 fragOffset, int32 *hdrIndex);
extern int32 dtlsHsHashFragMsg(ssl_t *ssl);
extern int32 dtlsCompareEpoch(unsigned char *incoming, unsigned char *expected);
extern void incrTwoByte(ssl_t *ssl, unsigned char *c, int sending);
extern void zeroTwoByte(unsigned char *c);
extern void dtlsIncrRsn(ssl_t *ssl);
extern void zeroSixByte(unsigned char *c);
extern int32 dtlsGenCookieSecret(void);
extern int32 dtlsEncryptFragRecord(ssl_t *ssl, flightEncode_t *msg,
				sslBuf_t *out, unsigned char **c);
#endif /* USE_DTLS */

/*
	cipherSuite.c
*/
extern int32 chooseCipherSuite(ssl_t *ssl, unsigned char *listStart,
				int32 listLen);
extern const sslCipherSpec_t *sslGetDefinedCipherSpec(uint16_t id);
extern const sslCipherSpec_t *sslGetCipherSpec(const ssl_t *ssl, uint16_t id);
extern int32_t sslGetCipherSpecListLen(const ssl_t *ssl);
extern int32_t sslGetCipherSpecList(ssl_t *ssl, unsigned char *c, int32 len,
				int32 addScsv);
extern int32_t haveKeyMaterial(const ssl_t *ssl, int32 cipherType, short reallyTest);
#ifdef USE_CLIENT_SIDE_SSL
int32 csCheckCertAgainstCipherSuite(int32 sigAlg, int32 cipherType);
#endif
extern void matrixSslSetKexFlags(ssl_t *ssl);

#ifndef DISABLE_SSLV3
/******************************************************************************/
/*
	sslv3.c
*/
extern int32_t sslGenerateFinishedHash(psMd5Sha1_t *md,
				const unsigned char *masterSecret,
				unsigned char *out, int32 senderFlag);

extern int32_t sslDeriveKeys(ssl_t *ssl);

#ifdef USE_SHA_MAC
extern int32 ssl3HMACSha1(unsigned char *key, unsigned char *seq,
						unsigned char type, unsigned char *data, uint32 len,
						unsigned char *mac);
#endif /* USE_SHA_MAC */

#ifdef USE_MD5_MAC
extern int32 ssl3HMACMd5(unsigned char *key, unsigned char *seq,
						unsigned char type, unsigned char *data, uint32 len,
						unsigned char *mac);
#endif /* USE_MD5_MAC */
#endif /* DISABLE_SSLV3 */

#ifdef USE_TLS
/******************************************************************************/
/*
	tls.c
*/
extern int32 tlsDeriveKeys(ssl_t *ssl);
extern int32 tlsExtendedDeriveKeys(ssl_t *ssl);
extern int32 tlsHMACSha1(ssl_t *ssl, int32 mode, unsigned char type,
						unsigned char *data, uint32 len, unsigned char *mac);

extern int32 tlsHMACMd5(ssl_t *ssl, int32 mode, unsigned char type,
						unsigned char *data, uint32 len, unsigned char *mac);
#ifdef  USE_SHA256
extern int32 tlsHMACSha2(ssl_t *ssl, int32 mode, unsigned char type,
						unsigned char *data, uint32 len, unsigned char *mac,
						int32 hashSize);
#endif

/******************************************************************************/

#ifdef USE_TLS_1_2
#if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH)
extern int32 sslSha1RetrieveHSHash(ssl_t *ssl, unsigned char *out);
#ifdef USE_SHA384
extern int32 sslSha384RetrieveHSHash(ssl_t *ssl, unsigned char *out);
#endif
#ifdef USE_SHA512
extern int32 sslSha512RetrieveHSHash(ssl_t *ssl, unsigned char *out);
#endif
#endif
#ifdef USE_CLIENT_SIDE_SSL
extern void sslSha1SnapshotHSHash(ssl_t *ssl, unsigned char *out);
#ifdef USE_SHA384
extern void sslSha384SnapshotHSHash(ssl_t *ssl, unsigned char *out);
#endif
#ifdef USE_SHA512
extern void sslSha512SnapshotHSHash(ssl_t *ssl, unsigned char *out);
#endif
#endif
#endif /* USE_TLS_1_2 */

extern int32_t extMasterSecretSnapshotHSHash(ssl_t *ssl, unsigned char *out,
				uint32 *outLen);

/******************************************************************************/
/*
	prf.c
*/
extern int32_t prf(const unsigned char *sec, uint16_t secLen,
				const unsigned char *seed, uint16_t seedLen,
				unsigned char *out, uint16_t outLen);
#ifdef USE_TLS_1_2
extern int32_t prf2(const unsigned char *sec, uint16_t secLen,
				const unsigned char *seed, uint16_t seedLen,
				unsigned char *out, uint16_t outLen, uint32_t flags);
#endif /* USE_TLS_1_2 */
#endif /* USE_TLS */

#ifdef USE_AES_CIPHER_SUITE
extern int32 csAesInit(sslSec_t *sec, int32 type, uint32 keysize);
extern int32 csAesEncrypt(void *ssl, unsigned char *pt,
					 unsigned char *ct, uint32 len);
extern int32 csAesDecrypt(void *ssl, unsigned char *ct,
					 unsigned char *pt, uint32 len);
#ifdef USE_AES_GCM
extern int32 csAesGcmInit(sslSec_t *sec, int32 type, uint32 keysize);
extern int32 csAesGcmEncrypt(void *ssl, unsigned char *pt,
					 unsigned char *ct, uint32 len);
extern int32 csAesGcmDecrypt(void *ssl, unsigned char *ct,
					 unsigned char *pt, uint32 len);
#endif
#endif /* USE_AES_CIPHER_SUITE */
#ifdef USE_3DES_CIPHER_SUITE
extern int32 csDes3Encrypt(void *ssl, unsigned char *pt,
					 unsigned char *ct, uint32 len);
extern int32 csDes3Decrypt(void *ssl, unsigned char *ct,
					 unsigned char *pt, uint32 len);
#endif /* USE_3DES_CIPHER_SUITE */
#ifdef USE_ARC4_CIPHER_SUITE
extern int32 csArc4Encrypt(void *ssl, unsigned char *pt,unsigned char *ct,
					uint32 len);
extern int32 csArc4Decrypt(void *ssl, unsigned char *pt,unsigned char *ct,
					uint32 len);
#endif /* USE_ARC4_CIPHER_SUITE */
#ifdef USE_SEED_CIPHER_SUITE
extern int32 csSeedEncrypt(void *ssl, unsigned char *pt,
					 unsigned char *ct, uint32 len);
extern int32 csSeedDecrypt(void *ssl, unsigned char *ct,
					 unsigned char *pt, uint32 len);
#endif /* USE_SEED_CIPHER_SUITE */

#ifdef USE_IDEA_CIPHER_SUITE
extern int32 csIdeaInit(sslSec_t *sec, int32 type, uint32 keysize);
extern int32 csIdeaEncrypt(void *ssl, unsigned char *pt,
					 unsigned char *ct, uint32 len);
extern int32 csIdeaDecrypt(void *ssl, unsigned char *ct,
					 unsigned char *pt, uint32 len);
#endif /* USE_IDEA_CIPHER_SUITE */

#ifdef USE_PSK_CIPHER_SUITE

extern int32_t matrixSslPskGetKey(ssl_t *ssl, 
				const unsigned char id[SSL_PSK_MAX_ID_SIZE], uint8_t idLen,
				unsigned char *key[SSL_PSK_MAX_KEY_SIZE], uint8_t *keyLen);
extern int32_t matrixSslPskGetKeyId(ssl_t *ssl,
				unsigned char *id[SSL_PSK_MAX_ID_SIZE], uint8_t *idLen,
				const unsigned char hint[SSL_PSK_MAX_HINT_SIZE], uint8_t hintLen);
extern int32_t matrixPskGetHint(ssl_t *ssl,
				unsigned char *hint[SSL_PSK_MAX_HINT_SIZE], uint8_t *hintLen);
#endif /* USE_PSK_CIPHER_SUITE */

#ifdef USE_ECC
extern int32 psTestUserEcID(int32 id, int32 ecFlags);
extern int32 curveIdToFlag(int32 id);
#endif

#ifdef USE_ECC_CIPHER_SUITE
extern int32_t eccSuitesSupported(const ssl_t *ssl,
		const uint16_t cipherSpecs[], uint8_t cipherSpecLen);
#endif /* USE_ECC_CIPHER_SUITE */

/******************************************************************************/
/* Deprected defines for compatibility */
#define CH_RECV_STAT			1
#define CH_SENT_STAT			2
#define SH_RECV_STAT			3
#define SH_SENT_STAT			4
#define ALERT_SENT_STAT			5
#define RESUMPTIONS_STAT		6
#define FAILED_RESUMPTIONS_STAT	7
#define APP_DATA_RECV_STAT		8
#define APP_DATA_SENT_STAT		9

#ifdef USE_MATRIXSSL_STATS
extern void matrixsslUpdateStat(ssl_t *ssl, int32_t type, int32_t value);
#else
static __inline
void matrixsslUpdateStat(ssl_t *ssl, int32_t type, int32_t value)
{
}
#endif /* USE_MATRIXSSL_STATS */

#ifdef __cplusplus
}
#endif

#endif /* _h_MATRIXSSLLIB */

/******************************************************************************/

